/**
 * Copyright (c) 2012, Hakans Pirates - 
 * Johan Andersson spaiki17@gmail.com, 
 * Mattias Lundberg lundberg.mattias@gmail.com, 
 * Samuel Sjodin sjoodin@gmail.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *  
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package pirates.terrain.water;

import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.asset.AssetManager;
import com.jme3.audio.AudioNode;
import com.jme3.audio.AudioRenderer;
import com.jme3.audio.LowPassFilter;
import com.jme3.material.Material;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
import com.jme3.post.filters.BloomFilter;
import com.jme3.post.filters.DepthOfFieldFilter;
import com.jme3.post.filters.LightScatteringFilter;
import com.jme3.renderer.Camera;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Node;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.texture.Texture2D;
import com.jme3.water.WaterFilter;
import pirates.Settings;

/**
 * 
 * @author Johan
 */
public class PostWaterState extends AbstractAppState {

	private Vector3f lightDir = new Vector3f(-4.9236743f, -1.27054665f,
			5.896916f);
	private WaterFilter water;
	TerrainQuad terrain;
	Material matRock;
	AudioNode waves;
	LowPassFilter underWaterAudioFilter = new LowPassFilter(0.5f, 0.1f);
	LowPassFilter underWaterReverbFilter = new LowPassFilter(0.5f, 0.1f);
	LowPassFilter aboveWaterAudioFilter = new LowPassFilter(1, 1);
	private SimpleApplication app;
	private Node rootNode;
	private AssetManager assetManager;
	private AppStateManager stateManager;
	private ViewPort viewPort;
	private Camera cam;
	private AudioRenderer audioRenderer;
	private final FilterPostProcessor fpp;

	public PostWaterState(SimpleApplication app) {

		this.app = app;
		this.rootNode = this.app.getRootNode();
		this.assetManager = this.app.getAssetManager();
		this.stateManager = this.app.getStateManager();
		this.viewPort = this.app.getViewPort();
		this.cam = this.app.getCamera();
		this.audioRenderer = this.app.getAudioRenderer();

		water = new WaterFilter(rootNode, lightDir);

		fpp = new FilterPostProcessor(assetManager);

		fpp.addFilter(water);
		BloomFilter bloom = new BloomFilter();
		bloom.setExposurePower(55);
		bloom.setBloomIntensity(1.0f);
		fpp.addFilter(bloom);
		LightScatteringFilter lsf = new LightScatteringFilter(
				lightDir.mult(-300));
		lsf.setLightDensity(1.0f);
		fpp.addFilter(lsf);
		DepthOfFieldFilter dof = new DepthOfFieldFilter();
		dof.setFocusDistance(0);
		dof.setFocusRange(100);
		fpp.addFilter(dof);

		fpp.setNumSamples(4);

		water.setWaveScale(0.003f);
		water.setMaxAmplitude(1f);
		water.setFoamExistence(new Vector3f(1f, 4, 0.5f));
		water.setFoamTexture((Texture2D) assetManager
				.loadTexture("Common/MatDefs/Water/Textures/foam2.jpg"));
		water.setNormalScale(0.5f);

		water.setRefractionConstant(0.25f);
		water.setRefractionStrength(0.5f);
		water.setFoamHardness(0.6f);

		water.setWaterHeight(initialWaterHeight);
		uw = cam.getLocation().y < waterHeight;

		waves = new AudioNode(assetManager,
				"Sounds/Environment/Ocean Waves.ogg");
		waves.setLooping(true);
		waves.setReverbEnabled(true);
		if (uw) {
			waves.setDryFilter(new LowPassFilter(0.5f, 0.1f));
		} else {
			waves.setDryFilter(aboveWaterAudioFilter);
		}
		audioRenderer.playSource(waves);
		viewPort.addProcessor(fpp);

	}
	// This part is to emulate tides, slightly varrying the height of the water
	// plane
	private float time = 0.0f;
	private float waterHeight = 0.0f;
	private float initialWaterHeight = 0.8f;
	private boolean uw = false;
	private float tpf = 0;
	private int runs = 0;
	private boolean ready = false;

	@Override
	public void update(float tpf) {
		if (!Settings.FANCY_WATER) {
			return;
		}
		time += tpf;
		waterHeight = (float) Math.cos(((time * 0.6f) % FastMath.TWO_PI)) * 1.5f;
		water.setWaterHeight(initialWaterHeight + waterHeight);
		if (water.isUnderWater() && !uw) {

			waves.setDryFilter(new LowPassFilter(0.5f, 0.1f));
			uw = true;
		}
		if (!water.isUnderWater() && uw) {
			uw = false;
			waves.setDryFilter(new LowPassFilter(1, 1f));

		}

		if (Settings.DYNAMIC_WATER_FANCINESS) {
			runs++;
			this.tpf += tpf;

			if (runs >= 30) {
				if (!ready) {
					ready = true;
				} else if (this.tpf > 1) {
					Settings.FANCY_WATER = false;
					stateManager.detach(this);
					viewPort.removeProcessor(fpp);
					SimpleWaterState simpleWater = new SimpleWaterState(app);
					stateManager.attach(simpleWater);
				}
				runs = 0;
				this.tpf = 0;
			}
		}

	}
}
